package com.example.musicplayer.service;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.BassBoost;
import android.media.audiofx.EnvironmentalReverb;
import android.media.audiofx.Virtualizer;
import android.media.audiofx.Visualizer;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.example.musicplayer.ActivityStackManager;
import com.example.musicplayer.DataLoadManager;
import com.example.musicplayer.MusicPlayerApplication;
import com.example.musicplayer.MusicStateChangedListener;
import com.example.musicplayer.commonUtils.PlayingNotification;
import com.example.musicplayer.commonUtils.StringUtil;
import com.example.musicplayer.commonUtils.Timer;
import com.example.musicplayer.commonUtils.ToastUtil;
import com.example.musicplayer.commonUtils.判断;
import com.example.musicplayer.musicTools.Lyric;
import com.example.musicplayer.musicTools.MusicListType;
import com.example.musicplayer.musicTools.MusicPlayMode;
import com.example.musicplayer.musicTools.MusicOp;
import com.example.musicplayer.musicClass.MusicInfo;
import com.example.musicplayer.R;
import com.example.musicplayer.musicClass.MusicMenu;
import com.example.musicplayer.musicClass.PlayingNotificationInfo;
import com.example.musicplayer.settings.MusicData;
import com.example.musicplayer.settings.MusicPlayerSettings;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class MusicService extends Service {
    private static final String TAG = "MusicService";
    private static final int HISTORY_MUSIC_COUNTS = 100;
    private static final int LISTEN_COUNTS_TIMER_INTERVAL = 500;
    //delete music from current music list
    public static final int DELETE_ONE = 0;
    public static final int DELETE_CURRENT = 1;
    public static final int DELETE_STATE_EMPTY = 2;
    //当前的播放音乐列表
    private final LinkedList<Integer> mHistoryMusicList = new LinkedList<Integer>();
    private List<MusicInfo> mMusicList = new ArrayList<MusicInfo>();
    private final MusicBinder mMusicBinder = new MusicBinder();
    private MediaPlayer mPlayer = null;
    private Visualizer mVisualizer;
    private BassBoost mBassBoost;
    private Virtualizer mVirtual;
    private EnvironmentalReverb mEnvironmentalReverb;
    //音频处理服务
    private AudioManager mAudioManager;
    private AudioFocusRequest mAudioFocusRequest;
    //记录是否持有音频焦点
    private boolean mHasAudioFocus = false;
    //当前音乐列表播放歌曲索引
    private int mIndex = -1;
    private int mLastIndex = -1;
    private int mNextIndex = -1;
    //if first start service and music prepared
    private boolean mFirstPrepared = true;
    //记录是否是在播放中被打断，用于恢复播放状态
    private boolean mInterruptedWhilePlaying = false;
    private MusicPlayMode mPlayMode = MusicPlayMode.RANDOM;
    //record the volume
    private float mCurrentVolume = 0.0f;
    private float mVolumeDelta;
    //about the music listen counts
    private int mMusicTimeCounts = 0;
    private int mCurrentMusicId = 0;
    //if now increasing the volume
    private boolean mVolumeIncreasing = true;
    private boolean mIsPlaying = false;
    private boolean mAllowPlayWithOther;
    private MusicServiceBroadcastReceiver mMusicServiceBroadcastReceiver;
    //监听音乐状态改变的监听者
    private List<MusicStateChangedListener> mMusicStateListener = new ArrayList<MusicStateChangedListener>();
    //播放前台发送通知类
    private PlayingNotification mPlayingNotification;
    //播放列表类型
    private MusicListType mMusicListType;
    private MusicMenu mCurrentMusicMenu;
    private Timer mVolumeTimer;
    private Timer mMusicListenCountsTimer;
    private Handler mHandler;

    //desktop lyric service connection
    private boolean mHasBindDesktopLyricService = false;
    private DesktopLyricService.DesktopLyricBinder mDesktopLyricBinder;
    private final ServiceConnection mDesktopLyricConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mDesktopLyricBinder = (DesktopLyricService.DesktopLyricBinder) service;
            mDesktopLyricBinder.setMusicBinder(mMusicBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mDesktopLyricBinder = null;
        }
    };

    //保存一次音乐播放状态
    private final Runnable mSaveRunnable = () -> {
        Log.d(TAG, "run(): save the music playing state");
        writeMusicData();
    };

    //监听音频焦点的变化
    private final AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener =
            new AudioManager.OnAudioFocusChangeListener() {
                @Override
                public void onAudioFocusChange(int focusChange) {
                    switch (focusChange) {
                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                            mHasAudioFocus = false;
                            if (!mAllowPlayWithOther) {
                                if (mMusicBinder.isPlaying()) {
                                    mInterruptedWhilePlaying = true;
                                    mMusicBinder.pause();
                                }
                            }
                            break;
                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                            if (!mAllowPlayWithOther && mMusicBinder.isPlaying()) {
                                mMusicBinder.setPlayVolume(0.3f);
                            }
                            break;
                        case AudioManager.AUDIOFOCUS_LOSS:
                            mHasAudioFocus = false;
                            if (!mAllowPlayWithOther) {
                                mMusicBinder.pause();
                            }
                            break;
                        case AudioManager.AUDIOFOCUS_GAIN:
                            mHasAudioFocus = true;
                            if (!mMusicBinder.isPlaying() && mInterruptedWhilePlaying) {
                                mMusicBinder.start();
                                mInterruptedWhilePlaying = false;
                            } else if (mMusicBinder.isPlaying()) {
                                mMusicBinder.start();
                            }
                            break;
                        default:
                            break;
                    }
                }
            };

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate(): MusicService create");
        super.onCreate();
        //注册广播
        mMusicServiceBroadcastReceiver = new MusicServiceBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(getString(R.string.notification_click));
        filter.addAction(getString(R.string.notification_favorite));
        filter.addAction(getString(R.string.notification_play));
        filter.addAction(getString(R.string.notification_last));
        filter.addAction(getString(R.string.notification_next));
        filter.addAction(getString(R.string.notification_lyric));
        filter.addAction(getString(R.string.notification_cancel));
        filter.addAction(getString(R.string.broadcast_allow_play_with_other));
        filter.addAction(getString(R.string.broadcast_use_notification_bar));
        filter.addAction(getString(R.string.broadcast_desktop_lyric));
        filter.addAction(getString(R.string.broadcast_desktop_lyric_lock));
        filter.addAction(getString(R.string.broadcast_desktop_lyric_in_app));
        filter.addAction(getString(R.string.broadcast_foreground_state_change));
        filter.addAction("android.intent.action.PHONE_STATE");
        filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
        registerReceiver(mMusicServiceBroadcastReceiver, filter);
        //获取音频服务
        mAudioManager = (AudioManager) getSystemService(Service.AUDIO_SERVICE);
        mAllowPlayWithOther = MusicPlayerSettings.allowPlayWithOther();
        //if enable desktop lyric
        if (MusicPlayerSettings.isDesktopLyric()) {
            enableDesktopLyricService(true);
        }
        mHandler = new Handler();
        initTimer();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand(): MusicService start");
        init();
        return Service.START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mMusicBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        destroyTimer();
        //stop desktop lyric service
        enableDesktopLyricService(false);
        mMusicList = null;
        if (mPlayer != null) {
            mPlayer.release();
        }
        mPlayer = null;
        unregisterReceiver(mMusicServiceBroadcastReceiver);
        abandonAudioFocus();
        if (mPlayingNotification != null) {
            mPlayingNotification.destroyNotification();
        }
    }

    private void initTimer() {
        //volume timer
        int refreshTime = getResources().getInteger(R.integer.music_volume_change_refresh_time);
        float time = getResources().getInteger(R.integer.music_volume_change_time);
        mVolumeDelta = (float) refreshTime / time;
        if (mVolumeDelta == 0.0f) {
            mVolumeDelta = 0.01f;
        }
        mVolumeTimer = new Timer(refreshTime, () -> {
            if (mPlayer != null) {
                //if pause, let it be in playing state
                if (!mPlayer.isPlaying()) {
                    mPlayer.start();
                }
                if (mVolumeIncreasing) {
                    mCurrentVolume += mVolumeDelta;
                    mCurrentVolume = Math.min(1.0f, mCurrentVolume);
                } else {
                    mCurrentVolume -= mVolumeDelta;
                    mCurrentVolume = Math.max(0.0f, mCurrentVolume);
                }
                mMusicBinder.setPlayVolume(mCurrentVolume);
                if (mCurrentVolume <= 0.0f || mCurrentVolume >= 1.0f) {
                    if (mCurrentVolume == 0.0f) {
                        mPlayer.pause();
                    } else {
                        mPlayer.start();
                    }
                    MusicPlayerApplication.removeTimer(mVolumeTimer);
                }
            }
        });
        //music listen counts timer
        mMusicListenCountsTimer = new Timer(LISTEN_COUNTS_TIMER_INTERVAL, () -> {
            int musicId = mMusicBinder.getId();
            if (musicId != mCurrentMusicId) {
                mCurrentMusicId = musicId;
                mMusicTimeCounts = 0;
            } else if (mMusicBinder.isPlaying()) {
                mMusicTimeCounts += LISTEN_COUNTS_TIMER_INTERVAL;
                int duration = mMusicBinder.getDuration();
                int limitTime = Math.min(duration, MusicPlayerSettings.getTimeToIncreaseListenCounts());
                if (mMusicTimeCounts > duration) {
                    mMusicTimeCounts -= duration;
                }
                if (mMusicTimeCounts >= limitTime && mMusicTimeCounts - LISTEN_COUNTS_TIMER_INTERVAL < limitTime) {
                    MusicInfo temp = MusicInfo.getMusicInfoById(mCurrentMusicId);
                    if (temp != null) {
                        temp.addListenCounts();
                    }
                }
            }
        });
    }

    private void destroyTimer() {
        MusicPlayerApplication.removeTimer(mVolumeTimer);
        MusicPlayerApplication.removeTimer(mMusicListenCountsTimer);
        mVolumeTimer = null;
        mMusicListenCountsTimer = null;
    }

    //一些初始化操作
    private void init() {
        if (mPlayer == null) {
            mPlayer = new MediaPlayer();
            mMusicBinder.setPlayVolume(mCurrentVolume);
            mMusicList.clear();
            MusicData musicData = null;
            if (DataLoadManager.getInstance() != null) {
                musicData = DataLoadManager.getInstance().readMusicData();
            }
            List<Integer> list = new ArrayList<Integer>();
            if (musicData != null) {
                list = musicData.getPlayList();
            }

            if (musicData != null && list.size() > 0) {
                try {
                    mMusicListType = MusicListType.valueOf(musicData.getMusicListType());
                } catch (Exception e) {
                    mMusicListType = MusicListType.TYPE_LOCAL;
                }
                try {
                    mPlayMode = MusicPlayMode.valueOf(musicData.getPlayMode());
                } catch (Exception e) {
                    mPlayMode = MusicPlayMode.RANDOM;
                }
                mCurrentMusicMenu = MusicInfo.getMusicMenuByName(musicData.getMusicMenuName());
                int musicId = musicData.getMusicId();
                int currentTime = musicData.getCurrentTime();
                for (int i = 0; i < list.size(); i++) {
                    MusicInfo musicInfo = MusicInfo.getMusicInfoById(list.get(i));
                    if (musicInfo != null)
                        mMusicList.add(musicInfo);
                }
                if (mMusicList.size() == 0) {
                    initNoMusicData();
                    initCurrentMusic(0, 0);
                } else {
                    int index = 0;
                    for (int i = 0; i < mMusicList.size(); i++)
                        if (mMusicList.get(i).getId() == musicId) {
                            index = i;
                            break;
                        }
                    initCurrentMusic(index, currentTime);
                }
            } else {
                initNoMusicData();
                initCurrentMusic(0, 0);
            }
            MusicPlayerApplication.addTimer(mMusicListenCountsTimer);
            checkSoundEffect();
        }
    }

    //获取音乐状态信息失败时，加载
    private void initNoMusicData() {
        mMusicListType = MusicListType.TYPE_LOCAL;
        mPlayMode = MusicPlayMode.RANDOM;
        initMusicList();
    }

    private void initCurrentMusic(int index, int currentTime) {
        mIndex = -1;
        mLastIndex = -1;
        mNextIndex = -1;
        if (index >= 0 && index < mMusicList.size())
            mIndex = index;
        addListener();
        mPlayingNotification = new PlayingNotification(this, this);
        //初始化播放本地音乐
        if (mMusicList.size() > 0) {
            try {
                mPlayer.reset();
                mPlayer.setDataSource(mMusicList.get(mIndex).getPath());
                mPlayer.prepare();
                mPlayer.seekTo(currentTime);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //初始化当前播放的音乐列表
    private void initMusicList() {
        mMusicList.clear();
        List<MusicInfo> list = MusicInfo.getLocalMusic();
        if (mMusicListType == null) {
            mMusicListType = MusicListType.TYPE_LOCAL;
        }
        //判断歌曲列表类型，向播放列表添加歌曲
        if (mMusicListType == MusicListType.TYPE_FAVORITE) {
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getFavorite() == 1) {
                    mMusicList.add(list.get(i));
                }
            }
        } else if (mMusicListType == MusicListType.TYPE_LOCAL || mMusicListType == MusicListType.TYPE_PURCHASED) {
            mMusicList = MusicInfo.getLocalMusic();
        } else if (mMusicListType == MusicListType.TYPE_MENU) {
            if (mCurrentMusicMenu != null) {
                List<Integer> musicId = MusicOp.sort(mCurrentMusicMenu.getName());
                for (int i = 0; i < musicId.size(); i++) {
                    MusicInfo temp = MusicInfo.getMusicInfoById(musicId.get(i));
                    if (temp != null) {
                        mMusicList.add(temp);
                    }
                }
            }
        }
    }

    //添加歌曲准备完成和播放完毕的监听器
    private void addListener() {
        mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                doAfterMusicPrepared();
            }
        });
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                doAfterMusicCompletion();
            }
        });
    }

    //发送更新通知
    private void sendNotification() {
        //当前列表有歌曲，才能更新通知
        if (MusicPlayerSettings.isUseNotificationBar() && mMusicList.size() > 0) {
            PlayingNotificationInfo info = new PlayingNotificationInfo(
                    mMusicList.get(mIndex).getTitle()
                    , mMusicList.get(mIndex).getArtist() + " - " + mMusicList.get(mIndex).getAlbum()
                    , mMusicList.get(mIndex).getBitmap()
                    , R.drawable.main_icon_blue
                    , mMusicBinder.getMusicFavorite() != 1 ? R.drawable.notification_not_favorite
                    : R.drawable.notification_favorite
                    , R.drawable.notification_last
                    , mMusicBinder.isPlaying() ? R.drawable.notification_start : R.drawable.notification_pause
                    , R.drawable.notification_next
                    , MusicPlayerSettings.isDesktopLyric()
                    ? (MusicPlayerSettings.isDesktopLyricLock()
                    ? R.drawable.notification_lyric_lock : R.drawable.notification_lyric_on)
                    : R.drawable.notification_lyric_off);
            mPlayingNotification.sendNotification(info, mMusicBinder.isPlaying());
        }
    }

    //check if enable any sound effect
    private void checkSoundEffect() {
        checkBassBoost();
        checkVirtual();
        checkEnvironmentalReverb();
    }

    //check if enable or disable bass boost
    private void checkBassBoost() {
        if (!MusicPlayerSettings.isEnableBassBoost() || mBassBoost != null) {
            if (mBassBoost != null) {
                mBassBoost.setEnabled(false);
                mBassBoost.release();
                mBassBoost = null;
            }
        }
        if (MusicPlayerSettings.isEnableBassBoost()) {
            if (mPlayer != null) {
                mBassBoost = new BassBoost(0, mPlayer.getAudioSessionId());
                mBassBoost.setEnabled(true);
                mBassBoost.setStrength((short) MusicPlayerSettings.getBassBoostStrength());
            }
        }
    }

    //check if enable virtual
    private void checkVirtual() {
        if (!MusicPlayerSettings.isEnableVirtual() || mVirtual != null) {
            if (mVirtual != null) {
                mVirtual.setEnabled(false);
                mVirtual.release();
                mVirtual = null;
            }
        }
        if (MusicPlayerSettings.isEnableVirtual()) {
            if (mPlayer != null) {
                mVirtual = new Virtualizer(0, mPlayer.getAudioSessionId());
                mVirtual.setEnabled(true);
                mVirtual.setStrength((short) MusicPlayerSettings.getVirtualStrength());
            }
        }
    }

    //check if enable reverb
    public void checkEnvironmentalReverb() {
        if (!MusicPlayerSettings.isEnableReverb() || mEnvironmentalReverb != null) {
            if (mEnvironmentalReverb != null) {
                mEnvironmentalReverb.setEnabled(false);
                mEnvironmentalReverb.release();
                mEnvironmentalReverb = null;
            }
        }
        if (MusicPlayerSettings.isEnableReverb()) {
            if (mPlayer != null) {
                mEnvironmentalReverb = new EnvironmentalReverb(0, mPlayer.getAudioSessionId());
                mEnvironmentalReverb.setEnabled(true);
                int level = MusicPlayerSettings.getReverbLevel();
                mEnvironmentalReverb.setRoomLevel((short) -5000);
                mEnvironmentalReverb.setReverbLevel((short) level);
            }
        }
    }

    //when music prepared, do something
    private void doAfterMusicPrepared() {
        //record the history music
        if (mHistoryMusicList.size() == HISTORY_MUSIC_COUNTS) {
            mHistoryMusicList.poll();
        }
        mHistoryMusicList.offer(mMusicBinder.getId());
        //get the last and next music index
        generateLastAndNextMusicIndex();
        //load the lyric file
        Lyric.create(mMusicBinder.getLyricPath(), getResources(), mMusicBinder.getId());
        if (mMusicStateListener != null) {
            for (MusicStateChangedListener listener : mMusicStateListener) {
                listener.musicPrepared(MusicInfo.getMusicInfoById(mMusicBinder.getId()));
            }
        }
        //notify the desktop lyric service
        if (mDesktopLyricBinder != null) {
            mDesktopLyricBinder.onMusicPrepared();
        }
        if (mPlayer != null && mMusicList.size() > 0) {
            sendNotification();
        }
        if (mMusicListType == MusicListType.TYPE_MENU && mCurrentMusicMenu != null && !mFirstPrepared) {
            mCurrentMusicMenu.setListenCounts();
        }
        writeMusicData();
        //check if need to exit app
        if (TimedOffService.getExitAppFlag()) {
            MusicPlayerApplication.getInstance().exit();
        }
        mFirstPrepared = false;
    }

    //when music play completed, do something
    private void doAfterMusicCompletion() {
        if (mMusicStateListener != null) {
            for (MusicStateChangedListener listener : mMusicStateListener) {
                listener.musicCompletion(MusicInfo.getMusicInfoById(mMusicBinder.getId()));
            }
        }
        if (mDesktopLyricBinder != null) {
            mDesktopLyricBinder.onMusicCompletion();
        }
        mMusicBinder.startNext();
    }

    private void generateLastAndNextMusicIndex() {
        if (mIndex < 0 || mIndex >= mMusicList.size()) {
            mIndex = 0;
        }
        switch (mPlayMode) {
            case RANDOM:
                mLastIndex = StringUtil.getRandom(0, mMusicList.size());
                mNextIndex = StringUtil.getRandom(0, mMusicList.size());
                //don't play the same music
                if (mLastIndex == mIndex) {
                    mLastIndex = (mIndex + mMusicList.size() - 1) % mMusicList.size();
                }
                if (mNextIndex == mIndex) {
                    mNextIndex = (mIndex + 1) % mMusicList.size();
                }
                break;
            case REPEAT:
                mLastIndex = (mIndex + mMusicList.size() - 1) % mMusicList.size();
                mNextIndex = (mIndex + 1) % mMusicList.size();
                break;
            case REPEAT_ONE:
                mLastIndex = mIndex;
                mNextIndex = mIndex;
                break;
        }
    }

    //写入音乐状态信息
    private void writeMusicData() {
        if (mPlayer != null) {
            String musicListType = mMusicListType == null ? MusicListType.TYPE_LOCAL.toString() : mMusicListType.toString();
            String playMode = mPlayMode == null ? MusicPlayMode.RANDOM.toString() : mPlayMode.toString();
            String musicMenuName = mCurrentMusicMenu == null ? " " : mCurrentMusicMenu.getName();
            int id = 0;
            int time = 0;
            List<Integer> list = new ArrayList<Integer>();
            for (int i = 0; i < mMusicList.size(); i++)
                list.add(mMusicList.get(i).getId());
            if (list.size() > 0) {
                id = mMusicList.get(mIndex).getId();
                time = mPlayer.getCurrentPosition();
            }
            if (DataLoadManager.getInstance() != null) {
                DataLoadManager.getInstance().writeMusicData(new MusicData(musicListType, playMode
                        , musicMenuName, id, time, list));
            }
        }
    }

    //尝试获取音频焦点
    private boolean gainAudioFocus() {
        if (mHasAudioFocus)
            return true;
        int result;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            if (mAudioFocusRequest == null)
                mAudioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                        .setOnAudioFocusChangeListener(mAudioFocusChangeListener).build();
            result = mAudioManager.requestAudioFocus(mAudioFocusRequest);
        } else {
            result = mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_MUSIC,
                    AudioManager.AUDIOFOCUS_GAIN);
        }
        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
            mHasAudioFocus = true;
        return mHasAudioFocus;
    }

    //放弃音频焦点
    private void abandonAudioFocus() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && mAudioFocusRequest != null) {
            mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
        } else {
            mAudioManager.abandonAudioFocus(mAudioFocusChangeListener);
        }
    }

    private void setPlayOrPause(boolean goPlaying) {
        mVolumeIncreasing = goPlaying;
        MusicPlayerApplication.addTimer(mVolumeTimer);
    }

    private void enableDesktopLyricService(boolean enable) {
        if (enable) {
            if (!mHasBindDesktopLyricService || mDesktopLyricBinder == null) {
                bindService(new Intent(this, DesktopLyricService.class),
                        mDesktopLyricConnection, BIND_AUTO_CREATE);
            }
            mHasBindDesktopLyricService = true;
        } else {
            if (mHasBindDesktopLyricService) {
                unbindService(mDesktopLyricConnection);
                mDesktopLyricBinder = null;
                mHasBindDesktopLyricService = false;
            }
        }
    }

    public class MusicBinder extends Binder {

        //音乐播放列表是否有音乐
        public boolean hasMusic() {
            return mPlayer != null && mMusicList.size() > 0;
        }

        public void setPlayVolume(float volume) {
            if (volume >= 0.0f && volume <= 1.0f) {
                mCurrentVolume = volume;
                mPlayer.setVolume(mCurrentVolume, mCurrentVolume);
            }
        }

        //开始播放歌曲
        public void start() {
            if (mPlayer != null && mMusicList.size() > 0) {
                if (gainAudioFocus()) {
                    //mPlayer.start();
                    mIsPlaying = true;
                    setPlayOrPause(true);
                    sendNotification();
                    if (mMusicStateListener != null && mMusicList.get(mIndex) != null) {
                        for (MusicStateChangedListener listener : mMusicStateListener) {
                            listener.musicPlayStateChanged(mMusicList.get(mIndex), true);
                        }
                    }
                    if (mDesktopLyricBinder != null) {
                        mDesktopLyricBinder.onPlayStateChanged(true);
                    }
                }
            }
        }

        //根据索引播放一首歌
        public void start(int index) {
            if (mPlayer != null && mMusicList.size() > 0 && index < mMusicList.size() && index >= 0) {
                mIndex = index;
                try {
                    mPlayer.reset();
                    mPlayer.setDataSource(mMusicList.get(mIndex).getPath());
                    mPlayer.prepare();
                    start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        public void start(List<MusicInfo> musicList, int position) {
            if (musicList != null && position >= 0 && position < musicList.size()) {
                pause();
                mMusicListType = MusicListType.TYPE_OTHER;
                mCurrentMusicMenu = null;
                //重置当前列表
                mMusicList.clear();
                mMusicList.addAll(musicList);
                mIndex = position;
                start(mIndex);
            }
        }

        //播放指定类型的音乐列表，从给定音乐开始
        public void start(MusicListType type, MusicMenu musicMenu, MusicInfo musicInfo) {
            //重置当前列表
            mPlayer.reset();
            //初始化类型和歌单对象
            mMusicListType = type;
            mCurrentMusicMenu = musicMenu;
            if (mMusicListType == MusicListType.TYPE_MENU && !MusicInfo.hasMusicMenu(mCurrentMusicMenu.getName())) {
                return;
            }
            initMusicList();
            mIndex = -1;
            if (musicInfo != null && mMusicList.size() > 0) {
                for (int i = 0; i < mMusicList.size(); i++) {
                    if (mMusicList.get(i).getId() == musicInfo.getId()) {
                        mIndex = i;
                        break;
                    }
                }
            }
            if (mIndex == -1) {
                mIndex = 0;
            }
            start(mIndex);
        }

        //the music menu and some music
        public void start(MusicMenu musicMenu, List<MusicInfo> musicList, MusicInfo musicInfo) {
            start(musicMenu, musicList, musicInfo, MusicListType.TYPE_MENU);
        }

        public void start(MusicMenu musicMenu, List<MusicInfo> musicList, MusicInfo musicInfo, MusicListType musicListType) {
            if (musicList == null) {
                return;
            }
            if (musicListType == MusicListType.TYPE_MENU && musicMenu == null) {
                return;
            }
            for (int i = 0; i < musicList.size(); i++) {
                if (musicList.get(i) == null) {
                    musicList.remove(i);
                    i--;
                }
            }
            if (musicList.size() > 0) {
                mPlayer.reset();
                mMusicList.clear();
                mMusicListType = musicListType;
                mCurrentMusicMenu = musicMenu;
                mMusicList.addAll(musicList);
                mIndex = -1;
                if (musicInfo != null && mMusicList.size() > 0) {
                    for (int i = 0; i < mMusicList.size(); i++) {
                        if (mMusicList.get(i).getId() == musicInfo.getId()) {
                            mIndex = i;
                            break;
                        }
                    }
                }
                if (mIndex == -1) {
                    mIndex = 0;
                }
                start(mIndex);
            }
        }

        //暂停播放
        public void pause() {
            if (mPlayer != null && mMusicList.size() > 0) {
                //mPlayer.pause();
                mIsPlaying = false;
                setPlayOrPause(false);
                sendNotification();
                if (mMusicStateListener != null && mMusicList.get(mIndex) != null) {
                    for (MusicStateChangedListener listener : mMusicStateListener) {
                        listener.musicPlayStateChanged(mMusicList.get(mIndex), false);
                    }
                }
                if (mDesktopLyricBinder != null) {
                    mDesktopLyricBinder.onPlayStateChanged(false);
                }
            }
        }

        public void changePlayingState() {
            if (isPlaying()) {
                pause();
            } else {
                start();
            }
        }

        //判断是否播放中
        public boolean isPlaying() {
            if (mPlayer != null && mMusicList.size() > 0) {
                return mIsPlaying;
            } else {
                return false;
            }
        }

        //播放上一首歌曲
        public void startLast() {
            if (mPlayer != null && mMusicList.size() > 0) {
                MusicInfo currentMusic = mMusicList.get(mIndex);
                if (mLastIndex < 0 || mLastIndex >= mMusicList.size()) {
                    generateLastAndNextMusicIndex();
                }
                mIndex = mLastIndex;
                if (mMusicStateListener != null) {
                    for (MusicStateChangedListener listener : mMusicStateListener) {
                        listener.musicPlayLast(currentMusic, mMusicList.get(mIndex));
                    }
                }
                start(mIndex);
            }
        }

        //播放下一首歌曲
        public void startNext() {
            if (mPlayer != null && mMusicList.size() > 0) {
                MusicInfo currentMusic = mMusicList.get(mIndex);
                if (mNextIndex < 0 || mNextIndex >= mMusicList.size()) {
                    generateLastAndNextMusicIndex();
                }
                mIndex = mNextIndex;
                if (mMusicStateListener != null) {
                    for (MusicStateChangedListener listener : mMusicStateListener) {
                        listener.musicPlayNext(currentMusic, mMusicList.get(mIndex));
                    }
                }
                start(mIndex);
            }
        }

        //跳转至给定时间处开始播放
        public void seekTo(int time) {
            if (mPlayer != null && mMusicList.size() > 0 && time <= mPlayer.getDuration()) {
                mPlayer.seekTo(time);
                start();
            }
        }

        //向播放列表中加入音乐
        public void addToPlayList(List<MusicInfo> musicList) {
            if (musicList != null) {
                for (int i = 0; i < musicList.size(); i++) {
                    if (musicList.get(i) == null) {
                        musicList.remove(i);
                        i--;
                    }
                }
                if (hasMusic()) {
                    int offset = MusicPlayerSettings.isAddToPlayListTail() ? mMusicList.size() : mIndex + 1;
                    for (int i = 0; i < musicList.size(); i++) {
                        mMusicList.add(offset + i, musicList.get(i));
                    }
                    //保存音乐播放状态
                    if (mHandler != null) {
                        mHandler.removeCallbacks(mSaveRunnable);
                        mHandler.postDelayed(mSaveRunnable, 1000);
                    }
                } else if (musicList.size() > 0) {
                    start(musicList, 0);
                }
                if (musicList.size() > 0) {
                    String text = musicList.size() + getString(R.string.add_to_play_list);
                    ToastUtil.makeToast(text);
                }
            }
        }

        //得到播放列表的歌曲数量
        public int getMusicCounts() {
            return mMusicList.size();
        }

        public int getFavoriteMusicCounts() {
            return MusicInfo.getFavoriteMusicCounts();
        }

        public int getMusicMenuCounts() {
            return MusicInfo.getMusicMenuCounts();
        }

        //得到当前歌曲在列表中的索引
        public int getNowMusicPosition() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                return mIndex;
            } else {
                return 0;
            }
        }

        public int getLastMusicPosition() {
            if (mLastIndex >= 0 && mLastIndex < mMusicList.size()) {
                return mLastIndex;
            } else {
                return 0;
            }
        }

        public int getNextMusicPosition() {
            if (mNextIndex >= 0 && mNextIndex < mMusicList.size()) {
                return mNextIndex;
            } else {
                return 0;
            }
        }

        //得到当前歌曲的id
        public int getId() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                return mMusicList.get(mIndex).getId();
            } else {
                return -1;
            }
        }

        //得到当前歌曲的歌名
        public String getTitle() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                return mMusicList.get(mIndex).getTitle();
            } else {
                return "";
            }
        }

        //得到当前歌曲的作者
        public String getArtist() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                return mMusicList.get(mIndex).getArtist();
            } else {
                return "";
            }
        }

        //获取专辑的图片
        public Bitmap getAlbumBitmap() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                return mMusicList.get(mIndex).getBitmap();
            } else {
                return null;
            }
        }

        //获取当前歌曲的时长
        public int getDuration() {
            if (mPlayer != null && mMusicList.size() > 0) {
                return mPlayer.getDuration();
            } else {
                return 0;
            }
        }

        //获取当前播放的时间进度
        public int getCurrent() {
            if (mPlayer != null) {
                return mPlayer.getCurrentPosition();
            } else {
                return 0;
            }
        }

        //获取歌曲的路径
        public String getPath() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                return mMusicList.get(mIndex).getPath();
            } else {
                return null;
            }
        }

        //获取歌曲歌词文件的路径
        public String getLyricPath() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                return mMusicList.get(mIndex).getLyricPath();
            }
            return null;
        }

        public MusicListType getMusicListType() {
            return mMusicListType;
        }

        //获取当前播放的模式
        public MusicPlayMode getMode() {
            return mPlayMode;
        }

        //得到歌曲被标志为喜爱的状态
        public int getMusicFavorite() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                return mMusicList.get(mIndex).getFavorite();
            }
            return 0;
        }

        //切换播放模式
        public void changeMode() {
            /*switch (mPlayMode) {
                case RANDOM:
                    mPlayMode = MusicPlayMode.REPEAT;
                    break;
                case REPEAT:
                    mPlayMode = MusicPlayMode.REPEAT_ONE;
                    break;
                case REPEAT_ONE:
                    mPlayMode = MusicPlayMode.RANDOM;
                    break;
            }*/
            判断.如果是(mPlayMode == MusicPlayMode.RANDOM).则(() -> {
                mPlayMode = MusicPlayMode.REPEAT;
            }).否则如果是(mPlayMode == MusicPlayMode.REPEAT).则(() -> {
                mPlayMode = MusicPlayMode.REPEAT_ONE;
            }).否则(() -> {
                mPlayMode = MusicPlayMode.RANDOM;
            });
            //re calculate last and next index
            generateLastAndNextMusicIndex();
            MusicInfo musicInfo = mMusicList.get(mIndex);
            if (mMusicStateListener != null && musicInfo != null && musicInfo.getId() == getId()) {
                for (MusicStateChangedListener listener : mMusicStateListener) {
                    listener.musicPlayModeChanged(musicInfo, mPlayMode);
                }
            }
            if (mDesktopLyricBinder != null) {
                mDesktopLyricBinder.onPlayModeChanged();
            }
        }

        //当前歌曲加到我喜欢
        public void changeToFavorite() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                MusicInfo.changeToFavorite(mMusicList.get(mIndex));
                sendNotification();
                if (mMusicStateListener != null) {
                    for (MusicStateChangedListener listener : mMusicStateListener) {
                        listener.musicFavoriteChanged(mMusicList.get(mIndex), true);
                    }
                }
                if (mDesktopLyricBinder != null) {
                    mDesktopLyricBinder.onMusicFavoriteChanged(true);
                }
            }
        }

        //改变歌曲的喜爱属性
        public void changeMusicFavorite() {
            if (mIndex >= 0 && mIndex < mMusicList.size()) {
                changeMusicFavorite(mMusicList.get(mIndex));
            }
        }

        //更爱favorite属性
        public void changeMusicFavorite(MusicInfo music) {
            MusicInfo.changeMusicFavorite(music);
            sendNotification();
            if (mMusicStateListener != null && music != null && music.getId() == getId()) {
                for (MusicStateChangedListener listener : mMusicStateListener) {
                    listener.musicFavoriteChanged(music, music.getFavorite() == 1);
                }
                if (mDesktopLyricBinder != null) {
                    mDesktopLyricBinder.onMusicFavoriteChanged(music.getFavorite() == 1);
                }
            }
        }

        //得到当前播放列表
        public List<MusicInfo> getMusicList() {
            return mMusicList;
        }

        public MusicInfo getMusicInfo(int position) {
            if (position >= 0 && position < mMusicList.size()) {
                return mMusicList.get(position);
            }
            return null;
        }

        public MusicMenu getMusicMenu(int order) {
            MusicMenu temp;
            for (int i = 0; i < getMusicMenuCounts(); i++) {
                temp = MusicInfo.getMusicMenus().get(i);
                if (temp != null && temp.getOrder() == order) {
                    return temp;
                }
            }
            return null;
        }

        public MusicMenu getPlayingMusicMenu() {
            if (mMusicListType == MusicListType.TYPE_MENU) {
                return mCurrentMusicMenu;
            }
            return null;
        }

        public boolean isPlayingFavoriteList() {
            return mMusicListType == MusicListType.TYPE_FAVORITE;
        }

        //delete one music and return a state
        public int deleteOneMusic(int position) {
            if (position != mIndex) {
                mMusicList.remove(position);
                if (position < mIndex) {
                    mIndex--;
                }
                generateLastAndNextMusicIndex();
                //用handler发送消息保存状态
                mHandler.removeCallbacks(mSaveRunnable);
                mHandler.postDelayed(mSaveRunnable, 1000);
                return DELETE_ONE;
            } else {
                if (mMusicList.size() == 1) {
                    return deleteAll();
                } else {
                    int target = position;
                    if (mNextIndex >= 0 && mNextIndex < mMusicList.size()) {
                        target = mNextIndex;
                    }
                    if (target == position) {
                        target = (target + 1) % mMusicList.size();
                    }
                    mIndex = target;
                    mMusicList.remove(position);
                    if (position < mIndex) {
                        mIndex--;
                    }
                    start(mIndex);
                }
            }
            return DELETE_CURRENT;
        }

        //delete all the music in music list
        public int deleteAll() {
            if (mPlayer != null) {
                MusicInfo lastMusicInfo = mMusicList.get(getNowMusicPosition());
                mPlayer.stop();
                mMusicList.clear();
                if (mMusicStateListener != null) {
                    for (MusicStateChangedListener listener : mMusicStateListener) {
                        listener.musicEmpty(lastMusicInfo);
                    }
                }
                if (mDesktopLyricBinder != null) {
                    mDesktopLyricBinder.onPlayListEmpty();
                }
                //保存状态信息
                writeMusicData();
                abandonAudioFocus();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    stopForeground(Service.STOP_FOREGROUND_REMOVE);
                }
            }
            return DELETE_STATE_EMPTY;
        }

        public void saveMusicPlayState() {
            writeMusicData();
        }

        //注册音乐状态改变监听器
        public void addMusicStateChangedListener(MusicStateChangedListener listener) {
            mMusicStateListener.remove(null);
            if (!mMusicStateListener.contains(listener)) {
                mMusicStateListener.add(listener);
            }
        }

        //移除监听
        public void removeMusicStateChangedListener(MusicStateChangedListener listener) {
            if (mMusicStateListener != null) {
                mMusicStateListener.remove(listener);
            }
        }

        public Binder getDesktopLyricBinder() {
            if (mHasBindDesktopLyricService) {
                return mDesktopLyricBinder;
            }
            return null;
        }

        public void enableVisualizer(boolean enable, final VisualizerListener listener) {
            if (mPlayer == null || getMusicCounts() == 0) {
                return;
            }
            if (enable) {
                if (mVisualizer == null) {
                    mVisualizer = new Visualizer(mPlayer.getAudioSessionId());
                    mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
                }
                mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
                    @Override
                    public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {
                        if (listener != null) {
                            listener.captureWaveFormData(waveform);
                        }
                    }

                    @Override
                    public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
                    }
                }, Visualizer.getMaxCaptureRate() / 2, true, false);
                mVisualizer.setEnabled(true);
            } else if (mVisualizer != null) {
                mVisualizer.release();
                mVisualizer = null;
            }
        }

        public void enableBassBoost(boolean enable) {
            if (MusicPlayerSettings.isEnableBassBoost() != enable) {
                MusicPlayerSettings.setEnableBassBoost(enable);
                checkBassBoost();
            }
        }

        public void setBassBoostStrength(int strength) {
            if (MusicPlayerSettings.isEnableBassBoost() && mBassBoost != null && strength >= 0 && strength <= 1000) {
                mBassBoost.setStrength((short) strength);
                MusicPlayerSettings.setBassBoostStrength(strength);
            }
        }

        public void enableVirtual(boolean enable) {
            if (MusicPlayerSettings.isEnableVirtual() != enable) {
                MusicPlayerSettings.setEnableVirtual(enable);
                checkVirtual();
            }
        }

        public void setVirtualStrength(int strength) {
            if (MusicPlayerSettings.isEnableVirtual() && mVirtual != null && strength >= 0 && strength <= 1000) {
                mVirtual.setStrength((short) strength);
                MusicPlayerSettings.setVirtualStrength(strength);
            }
        }

        public void enableReverb(boolean enable) {
            if (MusicPlayerSettings.isEnableReverb() != enable) {
                MusicPlayerSettings.setEnableReverb(enable);
                checkEnvironmentalReverb();
            }
        }

        public void setReverbLevel(int level) {
            if (MusicPlayerSettings.isEnableReverb() && mEnvironmentalReverb != null && level >= -9000 && level <= 2000) {
                mEnvironmentalReverb.setReverbLevel((short) level);
                mEnvironmentalReverb.setRoomLevel((short) -5000);
                MusicPlayerSettings.setReverbLevel(level);
            }
        }
    }

    public class MusicServiceBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (getString(R.string.notification_favorite).equals(intent.getAction())) {
                mMusicBinder.changeMusicFavorite();
            } else if (getString(R.string.notification_play).equals(intent.getAction())) {
                mMusicBinder.changePlayingState();
            } else if (getString(R.string.notification_last).equals(intent.getAction())) {
                mMusicBinder.startLast();
            } else if (getString(R.string.notification_next).equals(intent.getAction())) {
                mMusicBinder.startNext();
            } else if (getString(R.string.notification_lyric).equals(intent.getAction())) {
                String intentString;
                if (MusicPlayerSettings.isDesktopLyric()) {
                    if (MusicPlayerSettings.isDesktopLyricLock()) {
                        MusicPlayerSettings.setDesktopLyricLock(false);
                        intentString = getString(R.string.broadcast_desktop_lyric_lock);
                    } else {
                        MusicPlayerSettings.setDesktopLyric(false);
                        intentString = getString(R.string.broadcast_desktop_lyric);
                    }
                } else {
                    MusicPlayerSettings.setDesktopLyric(true);
                    intentString = getString(R.string.broadcast_desktop_lyric);
                }
                sendBroadcast(new Intent(intentString));
            } else if (getString(R.string.notification_cancel).equals(intent.getAction())) {
                if (mPlayingNotification != null)
                    mPlayingNotification.resetNotificationState();
            } else if (getString(R.string.notification_click).equals(intent.getAction())) {
                Intent activityIntent = new Intent(getApplicationContext(),
                        ActivityStackManager.getInstance().getTopActivity().getClass());
                activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(activityIntent);
            } else if (getString(R.string.broadcast_allow_play_with_other).equals(intent.getAction())) {
                mAllowPlayWithOther = MusicPlayerSettings.allowPlayWithOther();
                //if not allow, try to gain focus
                if (!mAllowPlayWithOther && mMusicBinder.isPlaying()) {
                    if (!gainAudioFocus()) {
                        mMusicBinder.pause();
                    }
                }
            } else if (getString(R.string.broadcast_use_notification_bar).equals(intent.getAction())) {
                if (MusicPlayerSettings.isUseNotificationBar()) {
                    sendNotification();
                } else {
                    mPlayingNotification.removeNotification();
                }
            } else if (getString(R.string.broadcast_desktop_lyric).equals(intent.getAction())) {
                enableDesktopLyricService(MusicPlayerSettings.isDesktopLyric());
                sendNotification();
            } else if (getString(R.string.broadcast_desktop_lyric_lock).equals(intent.getAction())) {
                if (mDesktopLyricBinder != null) {
                    mDesktopLyricBinder.onLockStateChanged(MusicPlayerSettings.isDesktopLyricLock());
                }
                sendNotification();
            } else if (getString(R.string.broadcast_desktop_lyric_in_app).equals(intent.getAction())) {
                if (mHasBindDesktopLyricService && mDesktopLyricBinder != null) {
                    mDesktopLyricBinder.showDesktopLyricView(MusicPlayerSettings.isDesktopLyricInApp() ||
                            !MusicPlayerApplication.getInstance().isForeground());
                }
            } else if (getString(R.string.broadcast_foreground_state_change).equals(intent.getAction())) {
                if (mHasBindDesktopLyricService && mDesktopLyricBinder != null && !MusicPlayerSettings.isDesktopLyricInApp()) {
                    mDesktopLyricBinder.showDesktopLyricView(!MusicPlayerApplication.getInstance().isForeground());
                }
            } else if ("android.intent.action.PHONE_STATE".equals(intent.getAction())) {
                TelephonyManager tm = (TelephonyManager) getSystemService(Service.TELEPHONY_SERVICE);
                switch (tm.getCallState()) {
                    case TelephonyManager.CALL_STATE_RINGING:
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        Log.d(TAG, "onReceive(): call state changed");
                        break;
                    case TelephonyManager.CALL_STATE_IDLE:
                        Log.d(TAG, "onReceive(): call state changed to idle");
                        break;
                    default:
                        break;
                }
            } else if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
                mMusicBinder.pause();
            }
        }
    }

    public interface VisualizerListener {
        void captureWaveFormData(byte[] waveform);
    }
}